package com.bondar.task3;

public class Buffer<T> {

	private T[] elements;
	private int end = 0;
	private int start = 0;
	private int filled = 0;

	@SuppressWarnings("unchecked")
	public Buffer(int N) {
		elements = (T[]) (new Object[N]);
	}

	public synchronized T get() throws InterruptedException {
		String threadName = Thread.currentThread().getName();
		
		while (isEmpty()) {
			System.out.println(String.format("%s: get wait", threadName));
			wait();
		}
		// remove oldest one
		System.out.println(String.format("%s:  get at [%d]: %s", threadName, start, elements[start]));
		T element = elements[start];
		elements[start] = null;
		start = start + 1 >= size() ? 0 : start + 1;
		filled--;
		notifyAll();

		System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		return element;
	}

	public synchronized void put(T element) throws InterruptedException {
		String threadName = Thread.currentThread().getName();
		
		while (isFull()) {
			System.out.println(threadName + ": buffer empty? "
					+ isEmpty() + " put wait, buffer free? " + (size() - filled)
					+ ", start: " + start + ", end: " + end);
			wait();
		}

		elements[end] = element;
		filled++;
		end++;
		end = end >= size() ? 0 : end;
		System.out.println(String.format("%s: put at [%d]: %s", threadName, end, element));
		System.out.println(String.format("%s: buffer empty? %b", threadName, isEmpty()));
		notifyAll();	    
		System.out.println("##################################");
	}

	public synchronized boolean isEmpty() {
		return filled == 0 && start == end;
	}

	public synchronized boolean isFull() {
		return filled == elements.length;
	}

	public int size() {
		return elements.length;
	}
}
